# main.py
import json
import os
import re
import subprocess
import sys
import time

import psutil
from PyQt5 import QtWidgets
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtGui import QClipboard
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox, QTableWidgetItem, QDialog, QLineEdit, QPushButton, \
    QFileDialog, QVBoxLayout, QHBoxLayout, QAbstractItemView

from FormatSelectionUI import FormatSelectionDialog
from RotatingSpinnerDIalog import RotatingSpinnerDialog
from VideoSelectDialogUI import VideoSelectionDialog
from cookies_util import CookieCopyThread

from database import TaskDatabase
from downloading_thread import DownloadTask

from DownloaderUI import Ui_MainWindow
from info_thread import InfoExtractor
from srt_thread import SrtThread
from task import Task
from utils import is_chrome_running

MAX_DOWNLOAD_THREADS = 1


class DownloaderApp(QMainWindow, Ui_MainWindow):
    current_tasks = []
    downloaded_tasks = []
    db = TaskDatabase()
    threads = []

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setFixedSize(800, 600)  # 默认大小
        self.setStyleSheet(open("style.qss", encoding="utf-8").read())  # 加载 QSS 样式

        self.save_directory = self.get_current_save_path()
        # 按钮连接
        self.pushButton.clicked.connect(self.add_task_dialog)
        self.pushButton_2.clicked.connect(self.open_settings)
        self.pushButton_3.clicked.connect(self.stop_selected_task)
        self.pushButton_4.clicked.connect(self.stop_all_tasks)
        # self.pushButton_5.clicked.connect(self.delete_selected_task)
        # self.pushButton_6.clicked.connect(self.delete_all)
        # self.pushButton_7.clicked.connect(self.resume_selected_task)
        # self.pushButton_8.clicked.connect(self.remove_paused_task)
        # self.pushButton_9.clicked.connect(self.remove_all_paused)
        # self.pushButton_10.clicked.connect(self.resume_all)
        # self.pushButton_11.clicked.connect(self.remove_selected_history)
        # self.pushButton_12.clicked.connect(self.clear_all_history)
        # self.pushButton_14.clicked.connect(self.remove_failed_task)
        # self.pushButton_15.clicked.connect(self.redownload_failed_task)
        # self.pushButton_17.clicked.connect(self.redownload_all_failed)
        # self.pushButton_18.clicked.connect(self.remove_all_failed)
        self.tableWidget.horizontalHeader().setStretchLastSection(True)
        self.tableWidget.horizontalHeader().setVisible(False)
        self.tableWidget.verticalHeader().setVisible(False)
        self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget.itemSelectionChanged.connect(self.on_downloading_task_selected)
        self.tableWidget_2.horizontalHeader().setStretchLastSection(True)
        self.tableWidget_2.horizontalHeader().setVisible(False)
        self.tableWidget_2.verticalHeader().setVisible(False)
        self.tableWidget_2.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget_2.cellDoubleClicked.connect(self.open_explorer)
        # self.tableWidget_3.horizontalHeader().setStretchLastSection(True)
        # self.tableWidget_3.horizontalHeader().setVisible(False)
        # self.tableWidget_3.verticalHeader().setVisible(False)
        # self.tableWidget_4.horizontalHeader().setStretchLastSection(True)
        # self.tableWidget_4.horizontalHeader().setVisible(False)
        # self.tableWidget_4.verticalHeader().setVisible(False)
        self.db.set_not_downloading()
        self.tabWidget.setCurrentIndex(0)
        self.show_current_tasks()
        self.show_history_tasks()
        if not is_chrome_running():
            self.statusBar.showMessage("正在从Chrome浏览器中复制YouTube Cookie")
            self.show_progressbar()
            self.pushButton.setEnabled(False)
            self.copyCookieThread = CookieCopyThread(self)
            self.copyCookieThread.copy_result.connect(self.show_cookie_copy_result)
            self.copyCookieThread.start()

        # self.info_extractor = InfoExtractor(self)
        # self.info_extractor.info_result.connect(self.show_add_tasks_dialog)
    def on_downloading_task_selected(self):
        self.pushButton_3.setEnabled(True)
        selected_items = self.tableWidget.selectedItems()
        if not selected_items:
            return

        row = selected_items[0].row()

    def show_progressbar(self):
        self.progressbar = RotatingSpinnerDialog(self)
        self.progressbar.start()

    def show_cookie_copy_result(self, is_success, message):
        self.progressbar.stop()
        if is_success:
            self.statusBar.showMessage("Cookie导入成功")
            self.pushButton.setEnabled(True)
        else:
            self.statusBar.clearMessage()
            ack = QMessageBox.warning(self, '错误', f'{message}, 是否要强制关闭Chrome浏览器重新复制Cookie',
                                      QMessageBox.Ok | QMessageBox.Cancel)
            # 如果OK，关闭运行的Chrome浏览器，
            if ack == QMessageBox.Ok:
                # 强制关闭 Chrome
                self.progressbar.start()
                self.force_kill_chrome()
                self.copyCookieThread.start()

    def force_kill_chrome(self):
        killed = 0
        for proc in psutil.process_iter(['name']):
            try:
                if proc.info['name'] and 'chrome' in proc.info['name'].lower():
                    proc.kill()
                    killed += 1
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                continue

    def show_history_tasks(self):
        tasks = self.db.get_downloaded_tasks()
        self.downloaded_tasks = tasks
        self.tableWidget_2.clear()
        self.tableWidget_2.setColumnCount(1)
        self.tableWidget_2.setRowCount(len(tasks))
        for i, t in enumerate(tasks):
            item = QTableWidgetItem(t.title)
            self.tableWidget_2.setItem(i, 0, item)

    def open_explorer(self, row, column):
        task = self.downloaded_tasks[row]
        file_path = os.path.join(task.path, f'{task.title}.mp4')
        if os.path.exists(file_path):
            if sys.platform.startswith('win'):
                # Windows：explorer /select,"C:\path\to\file"
                subprocess.run(['explorer', '/select,', os.path.normpath(file_path)])
            elif sys.platform.startswith('darwin'):
                # macOS：open -R "file_path"
                subprocess.run(['open', '-R', file_path])
            else:
                # Linux (可能无效，取决于文件管理器)
                # 用 nautilus 选中：nautilus --select "file_path"
                try:
                    subprocess.run(['nautilus', '--select', file_path])
                except FileNotFoundError:
                    # 回退为打开目录
                    subprocess.run(['xdg-open', os.path.dirname(file_path)])


    def stop_selected_task(self):
        #先判断TableWidget中是否有选中任务，如果选中了，从self.threads查找task.id == 选中任务的task.id, 然后停止这个任务
        pass

    def stop_all_tasks(self):
        pass

    def open_settings(self):
        # 创建设置对话框
        settings_dialog = QDialog(self)
        settings_dialog.setWindowTitle("设置")
        settings_dialog.resize(600, 120)

        # 创建保存路径输入框
        save_path_label = QLineEdit(settings_dialog)
        save_path_label.setPlaceholderText("请输入默认保存路径")
        save_path_label.setText(self.get_current_save_path())  # 假设这是获取当前保存路径的方法

        # 创建浏览按钮
        browse_button = QPushButton("浏览", settings_dialog)

        def browse():
            # 打开文件对话框选择目录
            folder = QFileDialog.getExistingDirectory(settings_dialog, "选择保存目录")
            save_path_label.setText(folder)

        browse_button.setFixedWidth(120)
        browse_button.clicked.connect(browse)

        # 创建保存按钮
        save_button = QPushButton("保存", settings_dialog)
        save_button.setFixedWidth(120)

        def save():
            new_save_path = save_path_label.text()
            if new_save_path:
                self.update_save_path(new_save_path)  # 假设这个方法更新保存路径
                settings_dialog.accept()  # 关闭对话框
            else:
                QMessageBox.warning(settings_dialog, "输入错误", "请确保填写保存路径")

        save_button.clicked.connect(save)

        # 设置对话框布局
        layout = QVBoxLayout(settings_dialog)
        layout.addWidget(save_path_label)
        horizontal_layout = QHBoxLayout()
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        horizontal_layout.addWidget(browse_button)
        horizontal_layout.addItem(spacerItem)
        horizontal_layout.addWidget(save_button)
        layout.addLayout(horizontal_layout)

        settings_dialog.setLayout(layout)
        settings_dialog.exec_()  # 显示设置对话框

    def new_task(self, url, path):
        ret, task_id = self.db.insert_task(url, path)
        task = self.db.get_task_by_id(task_id)

        # t = VideoInfoThread(self, task)

        def update_task_title(task):
            self.db.update_title(task.id, task.title)
            print(f'获取到任务Title；{task.id}/{task.title}')
            self.show_current_tasks()

        # t.get_video_info.connect(update_task_title)
        # t.start()
        if not ret:
            QMessageBox.warning(self, "错误", "请不要添加重复的任务")
            return
        # if len(self.threads) < 3:
        #     thread = DownloadingThread()
        self.show_current_tasks()

        # if len(self.threads) < 3:
        #     self.db.set_is_downloading(task.id)
        #     download_task = DownloadTask(self, task)
        #     download_task.progress_signal.connect(self.update_task_progress)
        #     download_task.finish_signal.connect(self.on_task_completed)
        #     download_task.fail_signal.connect(self.on_task_failed)
        #     download_task.start()
        #     self.db.set_is_downloading(task.id)

    def on_task_failed(self):
        pass

    def update_task_progress(self, id, downloaded, speed):
        print(f'task{id}', downloaded, speed)
        if not self.current_tasks:
            return
        for i, ct in enumerate(self.current_tasks):
            if ct.id == id:
                break
        if i == -1:
            print(f"❌ 没有找到任务 ID 为 {id} 的任务")
            return
        status_item = QTableWidgetItem(downloaded)
        speed_item = QTableWidgetItem(speed)
        self.tableWidget.setItem(i, 1, status_item)
        self.tableWidget.setItem(i, 2, speed_item)

    def on_task_failed(self, task, message):
        self.db.fail_task(task.id)
        self.statusBar.showMessage(f'{task.title} 下载失败')
        self.show_current_tasks()

    def remove_thread_by_task_id(self, task_id):
        for thread in self.threads:
            if thread.get_task_id() == task_id:
                self.threads.remove(thread)
                print(f"移除了线程: {task_id}")
                break

    def on_task_completed(self, task):
        i = 0
        for i, t in enumerate(self.current_tasks):
            if t.id == task.id:
                break
        speed_item = QTableWidgetItem('完成')
        self.tableWidget.setItem(i, 2, speed_item)
        self.remove_thread_by_task_id(task.id)
        self.show_current_tasks()
        print(f'任务完成{task}')


        def srt_begin(task):
            pass

        def srt_process(task, is_success, message):
            self.show_current_tasks()
            self.show_history_tasks()

        t = SrtThread(self, task)
        t.begin_download.connect(srt_begin)
        t.download_result.connect(srt_process)
        t.start()

    def show_current_tasks(self):
        self.current_tasks = self.db.get_downloading_tasks()
        if not self.current_tasks:
            self.tableWidget.clear()
            self.tableWidget.setRowCount(0)
            return
        if len(self.threads) < MAX_DOWNLOAD_THREADS:
            num = MAX_DOWNLOAD_THREADS - len(self.threads)
            for i in range(num):
                task = self.db.get_next_pending_task()
                if task:
                    self.db.set_is_downloading(task.id)
                    download_task = DownloadTask(self, task)
                    download_task.progress_signal.connect(self.update_task_progress)
                    download_task.finish_signal.connect(self.on_task_completed)
                    download_task.fail_signal.connect(self.on_task_failed)
                    download_task.start()
                    self.threads.append(download_task)
        self.update_current_tasks()

    def add_task_dialog(self):
        def on_url_parsed(info):
            self.progressbar.stop()

            if info.get('_type') == 'playlist':
                self.show_video_list(info)
            else:
                self.show_video_format_selection(info)

        def on_url_parsed_failed():
            self.progressbar.stop()
            ack = QMessageBox.warning(self, '错误', '被YouTube墙了，是否要强制关闭Chrome浏览器重新复制Cookie',
                                      QMessageBox.Ok | QMessageBox.Cancel)
            # 如果OK，关闭运行的Chrome浏览器，
            if ack == QMessageBox.Ok:
                # 强制关闭 Chrome
                self.progressbar.start()
                self.force_kill_chrome()
                self.copyCookieThread.start()

        clipboard: QClipboard = QApplication.clipboard()
        text = clipboard.text().strip()
        youtube_pattern = re.compile(
            r'(https?://)?(www\.)?(youtube\.com/(watch\?v=[\w-]+(&list=[\w-]+)?|playlist\?list=[\w-]+)|youtu\.be/[\w-]+)'
        )
        match = youtube_pattern.search(text)
        if match:
            url = match.group()
            self.show_progressbar()
            extractor = InfoExtractor(self)
            extractor.info_result.connect(on_url_parsed)
            extractor.extract(url)
            return

        # 创建对话框
        dialog = QDialog(self)
        dialog.setWindowTitle("添加下载任务")
        dialog.resize(600, 120)

        # # 创建输入框和按钮
        url_label = QLineEdit(dialog)
        url_label.setPlaceholderText("请输入视频链接")
        add_button = QPushButton("添加任务", dialog)
        add_button.setFixedWidth(120)

        def add_task():
            url = url_label.text()
            save_path = self.save_directory
            if url:
                # self.new_task(url, save_path)
                self.show_progressbar()
                extractor = InfoExtractor(self)
                extractor.info_result.connect(on_url_parsed)
                extractor.fail_result.connect(on_url_parsed_failed)
                extractor.extract(url)
                dialog.accept()  # 关闭对话框
            else:
                # 提示输入错误
                QMessageBox.warning(dialog, "输入错误", "请确保填写完整的链接和保存路径")

        add_button.clicked.connect(add_task)

        # 设置对话框布局
        layout = QVBoxLayout(dialog)
        layout.addWidget(url_label)
        # layout.addWidget(save_path_label)
        vertical_spacer = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum,
                                                QtWidgets.QSizePolicy.Expanding)  # 创建垂直间隔
        layout.addItem(vertical_spacer)  # 将垂直间隔添加到布局中
        horizontal_layout = QHBoxLayout()
        # horizontal_layout.addWidget(browse_button)
        spacer_item = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        horizontal_layout.addItem(spacer_item)
        horizontal_layout.addWidget(add_button)
        layout.addLayout(horizontal_layout)
        dialog.setLayout(layout)
        dialog.exec_()  # 显示对话框

    @pyqtSlot(Task)
    def update_current_tasks(self):
        self.show_tasks(self.tableWidget, self.current_tasks)

    def show_tasks(self, tableWidget, task_list):
        tableWidget.clear()
        tableWidget.setColumnCount(3)
        tableWidget.setColumnWidth(0, 500)
        tableWidget.setShowGrid(False)
        tableWidget.setRowCount(len(self.current_tasks))
        for i, t in enumerate(self.current_tasks):
            title_item = QTableWidgetItem()
            title_item.setText(t.title if t.title else t.url)
            status_item = QTableWidgetItem()
            status_item.setText('')
            speed_item = QTableWidgetItem()
            self.tableWidget.setItem(i, 0, title_item)
            self.tableWidget.setItem(i, 1, status_item)
            self.tableWidget.setItem(i, 2, speed_item)

    def show_video_list(self, info):
        dialog = VideoSelectionDialog(self, info)
        dialog.selected_result.connect(self.add_tasks)
        dialog.show()
        self.tabWidget.setCurrentIndex(0)
        pass

    def add_tasks(self, tasks, title):
        save_path = os.path.join(self.save_directory, title)
        if not os.path.exists(save_path):
            os.mkdir(save_path)
        if tasks:
            for t in tasks:
                t.path = os.path.join(self.save_directory, title)
            self.db.new_task_list(tasks)
        self.show_current_tasks()

    def show_video_format_selection(self, info):
        if info:
            dialog = FormatSelectionDialog(self, info)
            dialog.format_selected.connect(self.on_format_selected)
            dialog.show()
        else:
            QMessageBox.warning(self,'错误','没有解析到视频信息')

    def get_current_save_path(self):
        try:
            with open('run/config.json', 'r', encoding='utf-8') as f:
                configs = json.load(f)
                return configs['default_save_directory']
        except:
            default_dir = './downloads'
            if not os.path.exists(default_dir):
                os.mkdir(default_dir)
            return os.path.abspath(default_dir)

    def update_save_path(self, new_path):
        # 在这里更新保存路径
        self.save_directory = new_path
        with open('run/config.json', 'w', encoding='utf-8') as f:
            json.dump({'default_save_directory': new_path}, f, ensure_ascii=False)

    def on_format_selected(self,task):
        task.path = self.save_directory
        task.status = 0
        self.db.new_task(task)
        self.show_current_tasks()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = DownloaderApp()
    window.show()
    sys.exit(app.exec_())
